package com.example.demo.javaTest;

import com.example.demo.utils.*;
import org.junit.jupiter.api.Test;

import java.util.concurrent.*;

public class Threads {

    @Test
    public void testThread() {
        Thread t = new ThreadUtil("");
        t.start();

        for (int i = 0; i < 10; i++) {
            System.out.println("主线程" + Thread.currentThread().getName() + i);
        }
    }

    @Test
    public void testRunnable() {
        Runnable target = new RunnableUtil();
        new Thread(target).start();

        for (int i = 0; i < 10; i++) {
            System.out.println("主线程" + Thread.currentThread().getName() + i);
        }
    }

    @Test
    public void testRunnable2() {
//        Runnable target = new Runnable() {
//            @Override
//            public void run() {
//                for (int i = 0; i < 10; i++) {
//                    System.out.println("子线程" + Thread.currentThread().getName() + ":" + i);
//                }
//            }
//        };
//        new Thread(target).start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                System.out.println("子线程" + Thread.currentThread().getName() + ":" + i);
            }
        }).start();

        for (int i = 0; i < 10; i++) {
            System.out.println("主线程" + Thread.currentThread().getName() + i);
        }
    }

    @Test
    public void testCallable() throws ExecutionException, InterruptedException {
        Callable<String> call = new CallableUtil(100);
        FutureTask<String> f1 = new FutureTask<>(call);
        new Thread(f1).start();

        Callable<String> call2 = new CallableUtil(100);
        FutureTask<String> f2 = new FutureTask<>(call2);
        new Thread(f2).start();

        String rs = f1.get();
        System.out.println(rs);

        String rs2 = f2.get();
        System.out.println(rs2);

        for (int i = 0; i < 10; i++) {
            System.out.println("主线程" + Thread.currentThread().getName() + i);
        }
    }

    @Test
    public void testThreadMethod() throws InterruptedException {
        Thread t1 = new ThreadUtil("1号线程a");
        t1.start();
        System.out.println(t1.getName());

        Thread t2 = new ThreadUtil("");
        t2.setName("2号线程");
        t2.start();
        System.out.println(t2.getName());

        Thread t3 = new ThreadUtil("3号线程");
        t3.start();
        t3.join();//当前执行完再继续后续逻辑

        Thread t4 = new ThreadUtil("4号线程");
        t4.start();
        t4.join();

        Thread main = Thread.currentThread();
        main.setName("主线程");
        System.out.println(Thread.currentThread().getName());//main
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + i);
        }
    }

    @Test
    public void testSynchronized() {
        GetMoney getMoney = new GetMoney();
        Thread t1 = new Thread(() -> {
            getMoney.drawMoney(100000);
        });
        t1.setName("a");
        t1.start();
        Thread t2 = new Thread(() -> {
            getMoney.drawMoney(100000);
        });
        t2.setName("b");
        t2.start();

        GetMoney getMoney2 = new GetMoney();
        Thread t3 = new Thread(() -> {
            getMoney2.drawMoney(100000);
        });
        t3.setName("c");
        t3.start();
        Thread t4 = new Thread(() -> {
            getMoney2.drawMoney(100000);
        });
        t4.setName("d");
        t4.start();
    }

    @Test
    public void testSynchronizedBlock() {
        GetMoney getMoney = new GetMoney();
        Thread t1 = new Thread(() -> {
            getMoney.drawMoney2(100000);
        });
        t1.setName("a");
        t1.start();
        Thread t2 = new Thread(() -> {
            getMoney.drawMoney2(100000);
        });
        t2.setName("b");
        t2.start();

        GetMoney getMoney2 = new GetMoney();
        Thread t3 = new Thread(() -> {
            getMoney2.drawMoney2(100000);
        });
        t3.setName("c");
        t3.start();
        Thread t4 = new Thread(() -> {
            getMoney2.drawMoney2(100000);
        });
        t4.setName("d");
        t4.start();
    }

    @Test
    public void testLock() {
        GetMoney getMoney = new GetMoney();
        Thread t1 = new Thread(() -> {
            getMoney.drawMoney3(100000);
        });
        t1.setName("a");
        t1.start();
        Thread t2 = new Thread(() -> {
            getMoney.drawMoney3(100000);
        });
        t2.setName("b");
        t2.start();

        GetMoney getMoney2 = new GetMoney();
        Thread t3 = new Thread(() -> {
            getMoney2.drawMoney3(100000);
        });
        t3.setName("c");
        t3.start();
        Thread t4 = new Thread(() -> {
            getMoney2.drawMoney3(100000);
        });
        t4.setName("d");
        t4.start();
    }

    @Test
    public void testThreadCommunication() throws InterruptedException {
        Desk desk = new Desk();
        Thread t1 = new Thread(() -> {
            while (true){
                desk.put();
            }
        });
        t1.setName("厨师1");
        Thread t2 = new Thread(() -> {
            while (true){
                desk.put();
            }
        });
        t2.setName("厨师2");
        Thread t3 = new Thread(() -> {
            while (true){
                desk.put();
            }
        });
        t3.setName("厨师3");
        Thread t4 = new Thread(() -> {
            while (true){
                desk.eat();
            }
        });
        t4.setName("客人1");
        Thread t5 = new Thread(() -> {
            while (true){
                desk.eat();
            }
        });
        t5.setName("客人2");

        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();

        Thread.sleep(20*1000);//junit需添加主线程休眠，防止主线程执行完直接退出
    }

    @Test
    public void testThreadPoolRunnableExecute() throws InterruptedException {
//        ThreadPoolExecutor(int corePoolSize,
//        int maximumPoolSize,
//        long keepAliveTime,
//        TimeUnit unit,
//        BlockingQueue<Runnable> workQueue,
//        ThreadFactory threadFactory,
//        RejectedExecutionHandler handler)
        ExecutorService pool = new ThreadPoolExecutor(3, 5, 8,
                TimeUnit.SECONDS, new ArrayBlockingQueue<>(4), Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.CallerRunsPolicy());
//        new ThreadPoolExecutor.AbortPolicy();//直接报错
//        new ThreadPoolExecutor.CallerRunsPolicy();//主线程亲自服务
//        new ThreadPoolExecutor.DiscardOldestPolicy();//丢弃最老任务
//        new ThreadPoolExecutor.DiscardPolicy();//直接丢弃

        Runnable target = new RunnableUtil();
        pool.execute(target);//自动执行
        pool.execute(target);//自动执行
        pool.execute(target);//自动执行

        pool.execute(target);//复用前面核心线程
        pool.execute(target);//复用前面核心线程
        pool.execute(target);//复用前面核心线程
        pool.execute(target);
        //开始创建临时线程(需设置Runnable永久休眠)
        pool.execute(target);
        pool.execute(target);
        //开始拒绝
        pool.execute(target);

        pool.shutdown();//执行完再关闭
        //pool.shutdownNow();//立即关闭

        Thread.sleep(20*1000);//junit需添加主线程休眠，防止主线程执行完直接退出
    }

    @Test
    public void testThreadPoolCallableSubmit() throws InterruptedException, ExecutionException {
//        ThreadPoolExecutor(int corePoolSize,
//        int maximumPoolSize,
//        long keepAliveTime,
//        TimeUnit unit,
//        BlockingQueue<Runnable> workQueue,
//        ThreadFactory threadFactory,
//        RejectedExecutionHandler handler)
        ExecutorService pool = new ThreadPoolExecutor(3, 5, 8,
                TimeUnit.SECONDS, new ArrayBlockingQueue<>(4), Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.CallerRunsPolicy());
//        new ThreadPoolExecutor.AbortPolicy();//直接报错
//        new ThreadPoolExecutor.CallerRunsPolicy();//主线程亲自服务
//        new ThreadPoolExecutor.DiscardOldestPolicy();//丢弃最老任务
//        new ThreadPoolExecutor.DiscardPolicy();//直接丢弃

        Future<String> f1 = pool.submit(new CallableUtil(100));
        Future<String> f2 = pool.submit(new CallableUtil(200));
        Future<String> f3 = pool.submit(new CallableUtil(300));
        Future<String> f4 = pool.submit(new CallableUtil(400));

        System.out.println(f1.get());
        System.out.println(f2.get());
        System.out.println(f3.get());
        System.out.println(f4.get());

        pool.shutdown();//执行完再关闭
        //pool.shutdownNow();//立即关闭

        Thread.sleep(20*1000);//junit需添加主线程休眠，防止主线程执行完直接退出
    }

    @Test
    public void testNewFixedThreadPool() throws InterruptedException, ExecutionException {
        ExecutorService pool = Executors.newFixedThreadPool(3);

        Future<String> f1 = pool.submit(new CallableUtil(100));
        Future<String> f2 = pool.submit(new CallableUtil(200));
        Future<String> f3 = pool.submit(new CallableUtil(300));
        Future<String> f4 = pool.submit(new CallableUtil(400));

        System.out.println(f1.get());
        System.out.println(f2.get());
        System.out.println(f3.get());
        System.out.println(f4.get());

        pool.shutdown();//执行完再关闭
        //pool.shutdownNow();//立即关闭

        Thread.sleep(20*1000);//junit需添加主线程休眠，防止主线程执行完直接退出
    }

    @Test
    public void testNewSingleThreadExecutor() throws InterruptedException, ExecutionException {
        ExecutorService pool = Executors.newSingleThreadExecutor();

        Future<String> f1 = pool.submit(new CallableUtil(100));
        Future<String> f2 = pool.submit(new CallableUtil(200));
        Future<String> f3 = pool.submit(new CallableUtil(300));
        Future<String> f4 = pool.submit(new CallableUtil(400));

        System.out.println(f1.get());
        System.out.println(f2.get());
        System.out.println(f3.get());
        System.out.println(f4.get());

        pool.shutdown();//执行完再关闭
        //pool.shutdownNow();//立即关闭

        Thread.sleep(20*1000);//junit需添加主线程休眠，防止主线程执行完直接退出
    }

    @Test
    public void testPessimisticLock() throws InterruptedException {
        //1个变量，100个线程，每个线程加100次，每次+1
        Runnable target = new PessimisticLockAdder();
        for (int i = 0; i < 100; i++) {
            new Thread(target).start();
        }

        Thread.sleep(2*1000);//junit需添加主线程休眠，防止主线程执行完直接退出
    }

    @Test
    public void testOptimisticLock() throws InterruptedException {
        //1个变量，100个线程，每个线程加100次，每次+1
        Runnable target = new OptimisticLockAdder();
        for (int i = 0; i < 100; i++) {
            new Thread(target).start();
        }

        Thread.sleep(2*1000);//junit需添加主线程休眠，防止主线程执行完直接退出
    }


}
